/**
 *  Copyright 2009-2010 Steven Ottenhoff (Dual-IT)
 * 
 *  This file is part of Clazzified.
 *
 *  Clazzified is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Clazzified is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Clazzified.  If not, see http://www.gnu.org/licenses/gpl.
 * 
 */
package nl.dualit.clazzified.store.clazz;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import nl.dualit.clazzified.core.model.attribute.IAttribute;
import nl.dualit.clazzified.core.model.clazz.Clazz;
import nl.dualit.clazzified.store.AbstractStore;
import nl.dualit.clazzified.store.AttributeData;
import nl.dualit.clazzified.store.ClazzData;
import nl.dualit.clazzified.store.StoreConfiguration;
import nl.dualit.clazzified.store.clazz.db.dao.DaoDbFactory;
import nl.dualit.clazzified.store.db.AbstractDbHandler;
import nl.dualit.clazzified.store.db.HSQLDBHandler;

import org.apache.log4j.Logger;

/**
 * The ClazzStore is responsible for storing and retrieving the clazzes to and from
 * a persistent data source. 
 * 
 * @author Steven Ottenhoff
 *
 */
public class ClazzStore extends AbstractStore{	
		
	private final Logger log = Logger.getLogger( ClazzStore.class );
	private AbstractDbHandler handler;
	private IClazzDao clazzDao;
	private IAttributeDao attributeDao;
	private static ClazzStore store;
	
	/**
	 * Retrieve an instance of ClazzStore using default properties.
	 * 
	 * @return ClazzStore instance
	 */
	public static ClazzStore getInstance( ){
		if( StoreConfiguration.getProperties() == null )
			throw new NullPointerException( "Configuration properties has not been set." );
		if( store == null )
			store = new ClazzStore();
		
		return store;
	}
	
	/**
	 * Retrieve an instance of ClazzStore using custom properties.
	 * 
	 * @param properties
	 * @return
	 */
	public static ClazzStore getInstance( Properties properties ){
		if( properties == null )
			throw new NullPointerException( "Properties is null." );
		StoreConfiguration.setProperties( properties );
		return ClazzStore.getInstance();
	}
		
	private ClazzStore(){
		
		// TODO Handler and Factory based on configuration
		
		handler = new HSQLDBHandler();
		AbstractClazzDaoFactory factory = new DaoDbFactory( handler );
		clazzDao = factory.getClazzDao( );
		attributeDao = factory.getAttributeDao();
		
	}

	public void storeClazz( Clazz clazz ) throws NullPointerException {
		
		Long id = clazzDao.storeClazz( clazz.getDataMap() );
		
		if( id == null ){
			String message = "Did not recieve new id for clazz from store";
			log.error( message );
			throw new NullPointerException( message );
		}
		
		clazz.setId( id );
		
		for( IAttribute attribute : clazz.getAttributes() ){
			
			attributeDao.storeAttribute( attribute.getDataMap() );
		}
	}
	
	/**
	 * Store one or more new clazzes to persistent storage.
	 * 
	 * @param clazzes
	 * @return
	 */
	public void storeClazzes( List<Clazz> clazzes ){
		log.debug( "Request to store " + clazzes.size() + " clazzes." );
		for( Clazz clazz : clazzes ){
			if( clazz.getId() != null ){
				log.warn( "Ignoring request to store existing clazz with id = "+ clazz.getId() );
				break;
			}		
			
			storeClazz( clazz );
		}
		
	}
	
	public void updateClazz( Clazz clazz ){
		
	}
	
	/**
	 * Retrieve clazz data that matches clazzId.
	 * 
	 * @param clazzId
	 * @return
	 */
	public ClazzData getClazz( Long clazzId ){
		 
		 if( clazzId == null )
			throw new NullPointerException( "Clazz id is null, can't retrieve clazz" );
		 ClazzData clazzData = new ClazzData();
		 
		 clazzData.setClazzData( clazzDao.getClazzById( clazzId ) );
		
		 getClazzParts( clazzData );
		 		 
		 return clazzData;
	 }
	
	public ClazzData getClazz( String clazzName ){
		 
		 if( clazzName == null )
			throw new NullPointerException( "Clazz name is null, can't retrieve clazz" );
		 ClazzData clazzData = new ClazzData();
		 
		 clazzData.setClazzData( clazzDao.getClazzByName( clazzName ) );
		
		 getClazzParts( clazzData );
		 
		 return clazzData;
	 }
	
	private void getClazzParts( ClazzData clazzData ){
		
		// Get Attribute data
		clazzData.setAttributeData( getAttributesForClazz( Long.valueOf( 
				 clazzData.getClazzData().get( ClazzFields.CLAZZ_ID ) ) ) );
		 
		// Get Relation data
		
		// Get Manipulation data
	}
	
	
	
	public void deleteClazz( Clazz clazz ){
		 
		 // Delete Manipulations
		 
		 // Delete Relations
		 
		 // Delete Attributes
		 for( IAttribute attribute : clazz.getAttributes() )
			 deleteAttributeConstraints( attribute );
		 
		 // Delete Clazz
		 clazzDao.deleteClazz( clazz.getId() ); 
		
	 }
	 
	 public List<AttributeData> getAttributesForClazz( Long clazzId ){
		 
		 List<AttributeData> attributeList = new ArrayList<AttributeData>();
		 List<Map<AttributeFields,String> > attributes = attributeDao.getAttributesByClazzId( clazzId );
		 
		 for( Map<AttributeFields,String> attribute : attributes ){
			 AttributeData attributeData = new AttributeData();
			 attributeData.setAttributeMap( attribute );
			 
			 // Get constraints
			 
			 attributeList.add( attributeData );
		 }
		 
		 return attributeList;
	 }
	 
	 
	 public void updateAttribute( IAttribute attribute ){
		 
	 }
	 
	
	 public void deleteAttribute( IAttribute attribute ){
		  
		// Delete constraints
		deleteAttributeConstraints( attribute );
		
		
	 }
	 
	 public void deleteAttributeConstraints( IAttribute attribute ){
		 
	 }
	 
	 public void deleteAttributeConstraint( Long attributeId ){
		 
	 }

		
	@Override
	public void connect() {
		
		
	}

	@Override
	public boolean isAlive() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void synchronize() {
		// TODO Auto-generated method stub
		
	}
	
	
	
	@Override
	public void disconnect() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void buildStore() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void exportStore(String location, String format) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void importStore(String location, String format, boolean cleanFirst) {
		// TODO Auto-generated method stub
		
	}
	
	
}
